package negocio;

import datos.DetalleProgramacion;
import datos.Obra;
import datos.Programacion;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**
 *
 * @author Ing. Monica Merlo, Ing. Agustin  Fernandez
 */
@Stateless
public class GestorProgramacionBean implements GestorProgramacionRemote, GestorProgramacionLocal {

    static Logger logger = Logger.getLogger(GestorProgramacionBean.class);

    public static void log4j(Exception e) {
        URL url = GestorProgramacionBean.class.getResource("/configuracion/log4j.properties");
        PropertyConfigurator.configure(url);
        logger.error(e);
    }
    @PersistenceContext
    private EntityManager em;

    /***
     * Retorna una lista con todas las instancias de tipo DetalleProgramacion, que posean referencias
     * a una instancia de tipo Programacion, es decir que su id de Programacion coincida con
     * el parametro idProgramacion. En caso contrario retorna Null.
     * @param idProgramacion
     * @return la lista de los detalles de cada programacion de la obra
     * Interfaz remota
     */
    public List<DetalleProgramacion> verDetalleProgramacionesObraRemote(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("DetalleProgramacion.encontrarPorProgramacion");
            q.setParameter("idProgramacion", idProgramacion);
            return q.getResultList();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista con todas las instancias de tipo DetalleProgramacion, que posean referencias
     * a una instancia de tipo Programacion, es decir que su id de Programacion coincida con
     * el parametro idProgramacion. En caso contrario retorna Null.
     * @param idProgramacion
     * @return la lista de los detalles de cada programacion de la obra
     * Interfaz local
     */
    public List<DetalleProgramacion> verDetalleProgramacionesObra(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("DetalleProgramacion.encontrarPorProgramacion");
            q.setParameter("idProgramacion", idProgramacion);
            return q.getResultList();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista con todas aquellas instancias de Programacion, cuyo id Obra coincida con
     * el parametro idObra. En caso contrario retorna Null.
     * @param idObra
     * @return las programaciones de la obra
     * Interfaz local
     */
    public List<Programacion> verProgramacionesObra(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.encontrarPorObra");
            q.setParameter("idObra", idObra);
            return q.getResultList();

        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista con todas aquellas instancias de Programacion, cuyo id Obra coincida con
     * el parametro idObra. En caso contrario retorna Null.
     * @param idObra
     * @return las programaciones de la obra
     * Interfaz local
     */
    public List<Programacion> verProgramacionesObraRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.encontrarPorObra");
            q.setParameter("idObra", idObra);
            return q.getResultList();

        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista de motivos pertenecientes a la reprogramacion de la obra con
     * ID igual al parametro idObra.
     * @param idObra
     * @return los motivos de las reprogramaciones de la obra
     * Interfaz remota
     */
    public List<Programacion> verMotivosObraRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.motivosPorObra");
            q.setParameter("idObra", idObra);
            return q.getResultList();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista de motivos pertenecientes a la reprogramacion de la obra con
     * ID igual al parametro idObra.
     * @param idObra
     * @return los motivos de las reprogramaciones de la obra
     * Interfaz local
     */
    public List<Programacion> verMotivosObra(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.motivosPorObra");
            q.setParameter("idObra", idObra);
            return q.getResultList();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Agrega una nueva instancia de tipo DetalleProgramacion, en la BD, al realizar un alta de programacion, con todos sus atributos
     * y referencias a Clases relacionadas. Retorna True en caso de exito y False en caso contrario.
     * @param idObra
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @param tipo
     * @param p
     * @return true si el nuevo detalle de la programación persistió con éxito,
     * false si no persistió
     * Interfaz local
     */
    public boolean agregarDetalleProgramacion(int idObra, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo, String tipo, Programacion p) {
        try {
            DetalleProgramacion dp = new DetalleProgramacion();

            Programacion programacion = (Programacion) em.find(Programacion.class, p.getId());
            dp.setIdProgramacion(programacion);

            dp.setPeriodo(periodo.toUpperCase());
            dp.setAvancePrevisto(avancePrevisto);
            dp.setMontoPrevisto(montoPrevisto);

            if (montoReal.compareTo(BigDecimal.ZERO) >= 1) {
                dp.setMontoReal(montoReal);
            } else {
                dp.setMontoReal(BigDecimal.ZERO);
            }

            dp.setAvanceReal(avanceReal);


            float calcularRetraso = (avancePrevisto - avanceReal);
            if (calcularRetraso >= 0.0f) {
                dp.setRetraso(calcularRetraso);
            } else {
                dp.setRetraso(0.0f);
            }

            if (calcularRetraso > 20.00) {
                dp.setAlerta("ROJO");
            } else if (calcularRetraso > 10.00 && calcularRetraso <= 20.00) {
                dp.setAlerta("AMARILLO");
            } else {
                dp.setAlerta("VERDE");
            }

            persist(dp);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }

    }

    /***
     * Agrega una nueva instancia de tipo DetalleProgramacion, en la BD, al realizar un alta de programacion, con todos sus atributos
     * y referencias a Clases relacionadas. Retorna True en caso de exito y False en caso contrario.
     * @param idObra
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @param tipo
     * @param p
     * @return true si el nuevo detalle de la programación persistió con éxito,
     * false si no persistió
     * Interfaz remota
     */
    public boolean agregarDetalleProgramacionRemote(int idObra, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo, String tipo, Programacion p) {
        try {
            DetalleProgramacion dp = new DetalleProgramacion();

            Programacion programacion = (Programacion) em.find(Programacion.class, p.getId());
            dp.setIdProgramacion(programacion);

            dp.setPeriodo(periodo.toUpperCase());
            dp.setAvancePrevisto(avancePrevisto);
            dp.setMontoPrevisto(montoPrevisto);

            if (montoReal.compareTo(BigDecimal.ZERO) >= 1) {
                dp.setMontoReal(montoReal);
            } else {
                dp.setMontoReal(BigDecimal.ZERO);
            }

            dp.setAvanceReal(avanceReal);


            float calcularRetraso = (avancePrevisto - avanceReal);
            if (calcularRetraso >= 0.0f) {
                dp.setRetraso(calcularRetraso);
            } else {
                dp.setRetraso(0.0f);
            }

            if (calcularRetraso > 20.00) {
                dp.setAlerta("ROJO");
            } else if (calcularRetraso > 10.00 && calcularRetraso <= 20.00) {
                dp.setAlerta("AMARILLO");
            } else {
                dp.setAlerta("VERDE");
            }

            persist(dp);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }

    }

    /***
     * Agrega una nueva instancia de tipo Programacion, en la BD, al realizar un alta de programacion, con todos sus atributos
     * y referencias a Clases relacionadas. Retorna True en caso de exito y False en caso contrario.
     * @param idObra
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @param tipo
     * @return true si la programacion persistió con éxito, false si no persistió
     * Interfaz remota
     */
    public boolean agregarProgramacionRemote(int idObra, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo, String tipo) {
        try {
            Programacion p = new Programacion();
            p.setFecha(new Date(System.currentTimeMillis()));
            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            p.setTipo('P');
            p.setMotivo(motivo.toUpperCase());
            float calcularRetraso;
            calcularRetraso = (avancePrevisto - avanceReal);
            p.setRetraso(calcularRetraso);
            Obra obra = (Obra) em.find(Obra.class, idObra);
            p.setIdObra(obra);
            persist(p);
            em.flush();
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Agrega una nueva instancia de tipo Programacion, en la BD, al realizar un alta de programacion, con todos sus atributos
     * y referencias a Clases relacionadas. Retorna True en caso de exito y False en caso contrario.
     * @param idObra
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @param tipo
     * @return true si la programacion persistió con éxito, false si no persistió
     * Interfaz local
     */
    public boolean agregarProgramacion(int idObra, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo, String tipo) {
        try {
            Programacion p = new Programacion();
            p.setFecha(new Date(System.currentTimeMillis()));
            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            p.setTipo('P');
            p.setMotivo(motivo.toUpperCase());
            float calcularRetraso;
            calcularRetraso = (avancePrevisto - avanceReal);
            p.setRetraso(calcularRetraso);
            Obra obra = (Obra) em.find(Obra.class, idObra);
            p.setIdObra(obra);
            persist(p);
            em.flush();
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Modifica una instancia de tipo Programacion al encontrar previamente el ID de la
     * Programacion a actualizar. Retorna True si actualiza con exito la alerta y retraso
     * en Programacion segun datos de los detalles, false si no actualiza.
     * @param p
     * @param acumuladoRetraso
     * @return true si actualiza con exito alerta y retraso en Programacion segun datos de los detalles, false si no actualiza
     * Interfaz remota
     */
    public boolean actualizarProgramacionRemote(Programacion p, float acumuladoRetraso) {
        try {
            Programacion pr = (Programacion) em.find(Programacion.class, p.getId());
            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            pr.setRetraso(acumuladoRetraso);
            if (pr.getRetraso() > 20.00) {
                pr.setAlerta("ROJO");
            } else if (pr.getRetraso() > 10.00 && pr.getRetraso() <= 20.00) {
                pr.setAlerta("AMARILLO");
            } else {
                pr.setAlerta("VERDE");
            }
            persist(pr);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }

    }

    /***
     * Modifica una instancia de tipo Programacion al encontrar previamente el ID de la
     * Programacion a actualizar. Retorna True si actualiza con exito la alerta y retraso
     * en Programacion segun datos de los detalles, false si no actualiza.
     * @param p
     * @param acumuladoRetraso
     * @return true si actualiza con exito alerta y retraso en Programacion segun datos de los detalles, false si no actualiza
     * Interfaz local
     */
    public boolean actualizarProgramacion(Programacion p, float acumuladoRetraso) {
        try {
            Programacion pr = (Programacion) em.find(Programacion.class, p.getId());
            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            pr.setRetraso(acumuladoRetraso);
            if (pr.getRetraso() > 20.00) {
                pr.setAlerta("ROJO");
            } else if (pr.getRetraso() > 10.00 && pr.getRetraso() <= 20.00) {
                pr.setAlerta("AMARILLO");
            } else {
                pr.setAlerta("VERDE");
            }
            persist(pr);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }

    }

    /***
     * Actualiza fechaFin de una instancia de tipo Programacion al encontrar previamente el ID de la
     * Programacion a finalizar. Retorna True si actualiza con exito y False si no actualiza.
     * @param p
     * @return true si actualiza la fecha de fin de la programacion/reprogramacion, y false si no actualiza
     * Interfaz local
     */
    public boolean finProgramacion(Programacion p) {
        try {
            Programacion pr = (Programacion) em.find(Programacion.class, p.getId());
            pr.setFechaFin(new Date(System.currentTimeMillis()));
            persist(pr);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Actualiza fechaFin de una instancia de tipo Programacion al encontrar previamente el ID de la
     * Programacion a finalizar. Retorna True si actualiza con exito y False si no actualiza.
     * @param p
     * @return true si actualiza la fecha de fin de la programacion/reprogramacion, y false si no actualiza
     * Interfaz remota
     */
    public boolean finProgramacionRemote(Programacion p) {
        try {
            Programacion pr = (Programacion) em.find(Programacion.class, p.getId());
            pr.setFechaFin(new Date(System.currentTimeMillis()));
            persist(pr);
            return true;
        } catch (NoResultException nre) {
            return false;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /**
     * 
     * @param object
     */
    public void persist(Object object) {
        em.persist(object);
    }

    /***
     * Actualiza una instancia de tipo Programacion, al encontrar previamente el ID de la
     * Programacion, todos sus atributos. Retorna True si actualiza con exito y False si no actualiza.
     * @param idProgramacion
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @return true si el detalle de la programacion persistió con éxito, false si no persistió
     * Interfaz remota
     */
    public boolean modificarProgramacionRemote(int idProgramacion, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo) {
        try {
            DetalleProgramacion p = em.find(DetalleProgramacion.class, idProgramacion);
            p.setPeriodo(periodo.toUpperCase());

            p.setAvancePrevisto(avancePrevisto);
            p.setAvanceReal(avanceReal);
            p.setMontoPrevisto(montoPrevisto);
            p.setMontoReal(montoReal);
            float calcularRetraso = (avancePrevisto - avanceReal);
            if (calcularRetraso >= 0.0f) {
                p.setRetraso(calcularRetraso);
            } else {
                p.setRetraso(0.0f);
            }

            if (calcularRetraso > 20.00) {
                p.setAlerta("ROJO");
            } else if (calcularRetraso > 10.00 && calcularRetraso <= 20.00) {
                p.setAlerta("AMARILLO");
            } else {
                p.setAlerta("VERDE");
            }
            persist(p);
            em.flush();
            return true;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Actualiza una instancia de tipo Programacion, al encontrar previamente el ID de la
     * Programacion, todos sus atributos. Retorna True si actualiza con exito y False si no actualiza.
     * @param idProgramacion
     * @param periodo
     * @param fecha
     * @param avancePrevisto
     * @param avanceReal
     * @param montoPrevisto
     * @param montoReal
     * @param retraso
     * @param alerta
     * @param motivo
     * @return true si el detalle de la programacion persistió con éxito, false si no persistió
     * Interfaz local
     */
    public boolean modificarProgramacion(int idProgramacion, String periodo, Date fecha, float avancePrevisto, float avanceReal, BigDecimal montoPrevisto, BigDecimal montoReal, float retraso, String alerta, String motivo) {
        try {
            DetalleProgramacion p = em.find(DetalleProgramacion.class, idProgramacion);
            p.setPeriodo(periodo.toUpperCase());

            p.setAvancePrevisto(avancePrevisto);
            p.setAvanceReal(avanceReal);
            p.setMontoPrevisto(montoPrevisto);
            p.setMontoReal(montoReal);
            float calcularRetraso = (avancePrevisto - avanceReal);
            if (calcularRetraso >= 0.0f) {
                p.setRetraso(calcularRetraso);
            } else {
                p.setRetraso(0.0f);
            }

            if (calcularRetraso > 20.00) {
                p.setAlerta("ROJO");
            } else if (calcularRetraso > 10.00 && calcularRetraso <= 20.00) {
                p.setAlerta("AMARILLO");
            } else {
                p.setAlerta("VERDE");
            }
            persist(p);
            em.flush();
            return true;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Remueve una instancia de tipo DetalleProgramacion, al encontrar previamente su ID, definido
     * en el parametro idDetalleProgramacion.
     * @param idDetalleProgramacion
     * @return true si el detalle de la programación se eliminó con éxito, false si no se eliminó
     * Interfaz remota
     */
    public boolean eliminarProgramacionRemote(int idDetalleProgramacion) {
        try {
            DetalleProgramacion dp = em.find(DetalleProgramacion.class, idDetalleProgramacion);
            em.remove(dp);
            return true;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Remueve una instancia de tipo DetalleProgramacion, al encontrar previamente su ID, definido
     * en el parametro idDetalleProgramacion.
     * @param idDetalleProgramacion
     * @return true si el detalle de la programación se eliminó con éxito, false si no se eliminó
     * Interfaz local
     */
    public boolean eliminarProgramacion(int idDetalleProgramacion) {
        try {
            DetalleProgramacion p = em.find(DetalleProgramacion.class, idDetalleProgramacion);
            em.remove(p);
            return true;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return false;
        }
    }

    /***
     * Retorna la ultima instancia almacenada en la BD de tipo Programacion. Este método me trae
     * la programación actualizada a la GUI, es decir, primera vez muestra la Programación y eventualmente
     * las Reprogramaciones (ultima Programacion).
     * @param idObra Id de la obra actual
     * @return la última programacion.  Este método me trae la programación actualizada, es decir,
     *  1º vez la Programación y eventualmente las Reprogramaciones.
     * Interfaz remota
     */
    public Programacion programacionObraRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimaProgramacion");
            q.setParameter("idObra", idObra);
            Programacion p = (Programacion) q.getSingleResult();
            return p;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la ultima instancia almacenada en la BD de tipo Programacion. Este método me trae
     * la programación actualizada a la GUI, es decir, primera vez muestra la Programación y eventualmente
     * las Reprogramaciones (ultima Programacion).
     * @param idObra
     * @return la última programacion.  Este método me trae la programación actualizada, es decir,
     *  1º vez la Programación y eventualmente las Reprogramaciones.
     * Interfaz local
     */
    public Programacion programacionObra(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimaProgramacion");
            q.setParameter("idObra", idObra);
            Programacion p = (Programacion) q.getSingleResult();
            return p;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna, si existe, la fechaFin de la ultima instancia almacenada de Programacion, para
     * la Obra con ID igual al parametro idObra.
     * @param idObra
     * @return la fecha de fin de la ultima programacion para esa obra.
     * Interfaz local
     */
    public Date existeFechaFin(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.existeFechaFin");
            q.setParameter("idObra", idObra);
            return (Date) q.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna, si existe, la fechaFin de la ultima instancia almacenada de Programacion, para
     * la Obra con ID igual al parametro idObra.
     * @param idObra
     * @return la fecha de fin de la ultima programacion para esa obra.
     * Interfaz remota
     */
    public Date existeFechaFinRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.existeFechaFin");
            q.setParameter("idObra", idObra);
            return (Date) q.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la instancia de tipo Programacion con ID igual al valor
     * del parametro idProgramacion.
     * @param idProgramacion
     * @return id de la clase Programacion. Interfaz local
     */
    public Programacion traeIdProgramacion(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.findById");
            q.setParameter("id", idProgramacion);
            return (Programacion) q.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la instancia de tipo Programacion con ID igual al valor
     * del parametro idProgramacion.
     * @param idProgramacion
     * @return id de la clase Programacion. Interfaz remota
     */
    public Programacion traeIdProgramacionRemote(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.findById");
            q.setParameter("id", idProgramacion);
            return (Programacion) q.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la fecha de la primer instancia de Programacion almacenada
     * en la BD, perteneciente a la Obra con ID igual a idObra.
     * @param idObra
     * @return la menor fecha de creación de la programacion
     * Interfaz remota
     */
    public Date fechaCreacionRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.primerFecha");
            q.setParameter("idObra", idObra);
            Date primeraFecha = (Date) q.getSingleResult();
            return primeraFecha;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la fecha de la primer instancia de Programacion almacenada
     * en la BD, perteneciente a la Obra con ID igual a idObra.
     * @param idObra
     * @return la menor fecha de creación de la programacion
     * Interfaz local
     */
    public Date fechaCreacion(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.primerFecha");
            q.setParameter("idObra", idObra);
            Date primeraFecha = (Date) q.getSingleResult();
            return primeraFecha;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la ultima fecha de modificacion de las programaciones de la obra
     * con ID igual al valor del parametro idObra.
     * @param idObra
     * @return la ultima fecha de modificacion de las programaciones de la obra
     * Interfaz remota
     */
    public Date fechaModificacionRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimaFecha");
            q.setParameter("idObra", idObra);
            Date ultimaFecha = (Date) q.getSingleResult();
            return ultimaFecha;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna la ultima fecha de modificacion de las programaciones de la obra
     * con ID igual al valor del parametro idObra.
     * @param idObra
     * @return la ultima fecha de modificacion de las programaciones de la obra
     * Interfaz local
     */
    public Date fechaModificacion(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimaFecha");
            q.setParameter("idObra", idObra);
            Date ultimaFecha = (Date) q.getSingleResult();
            return ultimaFecha;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista con todas las instancias de tipo DetalleProgramacion que tengan
     * una referencia a una instancia de tipo Programacion.
     * @param idProgramacion
     * @return una lista con todas los detalles de programaciones realizados
     * Interfaz remota
     */
    public List<DetalleProgramacion> programacionesObraRemote(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("DetalleProgramacion.encontrarPorProgramacion");
            q.setParameter("idProgramacion", idProgramacion);
            return q.getResultList();
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna una lista con todas las instancias de tipo DetalleProgramacion que tengan
     * una referencia a una instancia de tipo Programacion.
     * @param idProgramacion
     * @return una lista con todas los detalles de programaciones realizados
     * Interfaz local
     */
    public List<DetalleProgramacion> programacionesObra(int idProgramacion) {
        try {
            javax.persistence.Query q = em.createNamedQuery("DetalleProgramacion.encontrarPorProgramacion");
            q.setParameter("idProgramacion", idProgramacion);
            return q.getResultList();
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna el ultimo motivo de reprogramacion de la obra con ID igual al
     * valor del parametro idObra.
     * @param idObra
     * @return el ultimo motivo de la reprogramacion
     * Interfaz remota
     */
    public String programacionesMotivoObraRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimoMotivo");
            q.setParameter("idObra", idObra);
            String ultimo = (String) q.getSingleResult();
            return ultimo;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /***
     * Retorna el ultimo motivo de reprogramacion de la obra con ID igual al
     * valor del parametro idObra.
     * @param idObra
     * @return el ultimo motivo de la reprogramacion
     * Interfaz local
     */
    public String programacionesMotivoObra(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.ultimoMotivo");
            q.setParameter("idObra", idObra);
            String ultimo = (String) q.getSingleResult();
            return ultimo;
        } catch (NoResultException nre) {
            return null;
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
            return null;
        }
    }

    /**
     * Almacena una nueva reprogramacion de la Obra.
     * @param idProgramacion
     * @param motivo
     * persiste la reprogramacion
     * Interfaz remota
     */
    public void reprogramarRemote(int idProgramacion, String motivo) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.findById");
            q.setParameter("id", idProgramacion);
            Programacion p = (Programacion) q.getSingleResult();
            Programacion backUp = new Programacion();
            backUp.setAlerta(p.getAlerta());

            backUp.setFecha(p.getFecha());
            backUp.setFechaModificacion(p.getFechaModificacion());
            backUp.setTipo(p.getTipo());
            backUp.setRetraso(p.getRetraso());
            backUp.setIdObra(p.getIdObra());
            backUp.setMotivo(p.getMotivo());
            backUp.setFechaFin(p.getFechaFin());
            persist(backUp);

            List<DetalleProgramacion> dp = (List<DetalleProgramacion>) this.verDetalleProgramacionesObra(idProgramacion);
            List<DetalleProgramacion> ldp = new ArrayList<DetalleProgramacion>();

            for (DetalleProgramacion d : dp) {
                DetalleProgramacion dp1 = new DetalleProgramacion();
                dp1.setAlerta(d.getAlerta());
                dp1.setAvancePrevisto(d.getAvancePrevisto());
                dp1.setAvanceReal(d.getAvanceReal());
                dp1.setIdProgramacion(backUp);
                dp1.setMontoPrevisto(d.getMontoPrevisto());
                dp1.setMontoReal(d.getMontoReal());
                dp1.setPeriodo(d.getPeriodo());
                dp1.setRetraso(d.getRetraso());
                ldp.add(dp1);
                persist(dp1);

            }
            backUp.setDetalleProgramacionCollection(ldp);
            persist(backUp);

            if (p.getTipo() == 'P') {
                p.setTipo('R');
            }

            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            p.setMotivo(motivo.toUpperCase());
            p.setFechaFin(null);
            persist(p);

            em.flush();
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
        }
    }

    /***
     * Almacena una nueva reprogramacion de la Obra.
     * @param idProgramacion
     * @param motivo
     * persiste la reprogramacion
     * Interfaz local
     */
    public void reprogramar(int idProgramacion, String motivo) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Programacion.findById");
            q.setParameter("id", idProgramacion);
            Programacion p = (Programacion) q.getSingleResult();
            Programacion backUp = new Programacion();
            backUp.setAlerta(p.getAlerta());

            backUp.setFecha(p.getFecha());
            backUp.setFechaModificacion(p.getFechaModificacion());
            backUp.setTipo(p.getTipo());
            backUp.setRetraso(p.getRetraso());
            backUp.setIdObra(p.getIdObra());
            backUp.setMotivo(p.getMotivo());
            backUp.setFechaFin(p.getFechaFin());
            persist(backUp);

            List<DetalleProgramacion> dp = (List<DetalleProgramacion>) this.verDetalleProgramacionesObra(idProgramacion);
            List<DetalleProgramacion> ldp = new ArrayList<DetalleProgramacion>();

            for (DetalleProgramacion d : dp) {
                DetalleProgramacion dp1 = new DetalleProgramacion();
                dp1.setAlerta(d.getAlerta());
                dp1.setAvancePrevisto(d.getAvancePrevisto());
                dp1.setAvanceReal(d.getAvanceReal());
                dp1.setIdProgramacion(backUp);
                dp1.setMontoPrevisto(d.getMontoPrevisto());
                dp1.setMontoReal(d.getMontoReal());
                dp1.setPeriodo(d.getPeriodo());
                dp1.setRetraso(d.getRetraso());
                ldp.add(dp1);
                persist(dp1);

            }
            backUp.setDetalleProgramacionCollection(ldp);
            persist(backUp);

            if (p.getTipo() == 'P') {
                p.setTipo('R');
            }

            p.setFechaModificacion(new Date(System.currentTimeMillis()));
            p.setMotivo(motivo.toUpperCase());
            p.setFechaFin(null);
            persist(p);

            em.flush();
        } catch (Exception e) {
            GestorProgramacionBean.log4j(e);
        }
    }
}
